import akshare as ak
import pandas as pd
from typing import Dict, List, Optional
import numpy as np
import requests
from bs4 import BeautifulSoup
import re
import time
from datetime import datetime
import logging

# 配置日志
logger = logging.getLogger(__name__)

class CapitalFlowData:
    """资金流向数据类
    处理主力资金流向、北向资金、行业板块资金和融资融券数据等资金相关数据
    """
    
    def __init__(self, ts_token: str = None):
        """初始化资金流向数据类
        
        Args:
            ts_token: 为了保持兼容性保留此参数，但使用 AKShare 时不需要
        """        
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
            'Referer': 'http://data.eastmoney.com/'
        }
    
    def get_moneyflow(self, stock_code: str, start_date: str, end_date: str) -> Optional[Dict]:
        """获取个股资金流向数据
        
        Args:
            stock_code: 股票代码（如：000001 或 000001.SZ）
            start_date: 开始日期，格式YYYYMMDD
            end_date: 结束日期，格式YYYYMMDD
            
        Returns:
            包含大单、超大单资金净流入/流出数据的字典
        """
        try:
            logger.info(f"开始获取股票 {stock_code} 的资金流向数据")
            logger.debug(f"请求参数: start_date={start_date}, end_date={end_date}")
            
            # 处理股票代码格式
            base_code = stock_code.split('.')[0] if '.' in stock_code else stock_code
            # 根据股票代码开头判断市场并添加后缀
            if base_code.startswith('6'):
                formatted_code = f"{base_code}.sh"
            else:
                formatted_code = f"{base_code}.sz"
            logger.debug(f"处理后的股票代码: {formatted_code}")
            
            # 使用 AKShare 获取资金流向数据
            logger.info("调用AKShare API获取资金流向数据...")
            try:
                # 根据股票代码判断市场类型
                market = "sh" if base_code.startswith('6') else "sz"
                logger.debug(f"使用市场类型: {market}")
                df = ak.stock_individual_fund_flow(stock=base_code, market=market)
                if df is None:
                    logger.warning("AKShare API返回None")
                    return None
                else:
                    logger.debug("AKShare API返回数据成功")
                    logger.debug(f"数据列名: {df.columns.tolist()}")
                    logger.debug(f"数据行数: {len(df)}")
            except Exception as api_e:
                logger.error(f"AKShare API调用失败: {api_e}")
                df = pd.DataFrame()
            
            if df.empty:
                logger.info("AKShare API返回空数据，尝试使用爬虫方式获取...")
                df = self._crawl_moneyflow_data(stock_code)
                if df.empty:
                    logger.warning("爬虫方式也未获取到数据")
                    return None
            
            # 筛选日期范围内的数据
            logger.info("处理日期格式并筛选数据...")
            df['trade_date'] = pd.to_datetime(df['日期']).dt.strftime('%Y%m%d')
            df = df[(df['trade_date'] >= start_date) & (df['trade_date'] <= end_date)]
            
            logger.info(f"筛选后的数据行数: {len(df)}")
            
            # 按日期升序排序
            df = df.sort_values('trade_date')
            
            result = {
                'trade_date': df['trade_date'].values,
                'buy_sm_amount': df['小单净流入-净额'].values,  # 小单买入金额
                'buy_md_amount': df['中单净流入-净额'].values,  # 中单买入金额
                'buy_lg_amount': df['大单净流入-净额'].values,  # 大单买入金额
                'buy_elg_amount': df['超大单净流入-净额'].values,  # 超大单买入金额
                'net_mf_amount': df['主力净流入-净额'].values  # 净流入金额
            }
            
            logger.info("数据处理完成")
            logger.debug(f"结果数据量: {len(result['trade_date'])}条")
            if len(result['trade_date']) > 0:
                logger.debug(f"首条数据: 日期={result['trade_date'][0]}, 主力净流入={result['net_mf_amount'][0]}")
            
            return result
        except Exception as e:
            logger.error(f"获取个股资金流向数据失败: {type(e).__name__} - {str(e)}")
            
            # 尝试使用爬虫方式获取
            try:
                logger.info("尝试使用爬虫方式获取资金流向数据...")
                df = self._crawl_moneyflow_data(stock_code)
                if df.empty:
                    logger.warning("爬虫获取数据失败")
                    return None
                
                logger.info("爬虫获取数据成功，开始处理数据...")
                # 筛选日期范围内的数据
                df['trade_date'] = pd.to_datetime(df['日期']).dt.strftime('%Y%m%d')
                df = df[(df['trade_date'] >= start_date) & (df['trade_date'] <= end_date)]
                
                logger.info(f"筛选后的数据行数: {len(df)}")
                
                # 按日期升序排序
                df = df.sort_values('trade_date')
                
                result = {
                    'trade_date': df['trade_date'].values,
                    'buy_sm_amount': df['小单净流入-净额'].values,
                    'buy_md_amount': df['中单净流入-净额'].values,
                    'buy_lg_amount': df['大单净流入-净额'].values,
                    'buy_elg_amount': df['超大单净流入-净额'].values,
                    'net_mf_amount': df['主力净流入-净额'].values
                }
                
                logger.info("爬虫数据处理完成")
                logger.debug(f"结果数据量: {len(result['trade_date'])}条")
                if len(result['trade_date']) > 0:
                    logger.debug(f"首条数据: 日期={result['trade_date'][0]}, 主力净流入={result['net_mf_amount'][0]}")
                
                return result
            except Exception as e2:
                logger.error(f"爬虫获取资金流向数据也失败: {type(e2).__name__} - {str(e2)}")
                return None
    
    def _crawl_moneyflow_data(self, stock_code: str) -> pd.DataFrame:
        """使用爬虫方式获取个股资金流向数据
        
        Args:
            stock_code: 股票代码
            
        Returns:
            包含资金流向数据的DataFrame
        """
        try:
            # 构建东方财富网资金流向页面URL
            market_code = '1' if stock_code.startswith('6') else '0'
            url = f"http://data.eastmoney.com/zjlx/{stock_code}.html"
            
            # 发送请求获取页面内容
            response = requests.get(url, headers=self.headers, timeout=10)
            response.encoding = 'utf-8'
            
            if response.status_code != 200:
                print(f"请求失败，状态码: {response.status_code}")
                return pd.DataFrame()
            
            # 使用BeautifulSoup解析HTML
            soup = BeautifulSoup(response.text, 'html.parser')
            
            # 查找资金流向数据表格
            table = soup.find('table', id='content_zjlx_table')
            if not table:
                print("未找到资金流向数据表格")
                return pd.DataFrame()
            
            # 解析表格数据
            rows = table.find_all('tr')
            data = []
            
            for row in rows[1:]:  # 跳过表头行
                cols = row.find_all('td')
                if len(cols) >= 12:  # 确保列数足够
                    date = cols[0].text.strip()
                    main_net = self._parse_money_value(cols[1].text)
                    main_net_pct = self._parse_percentage(cols[2].text)
                    super_large_net = self._parse_money_value(cols[3].text)
                    super_large_net_pct = self._parse_percentage(cols[4].text)
                    large_net = self._parse_money_value(cols[5].text)
                    large_net_pct = self._parse_percentage(cols[6].text)
                    medium_net = self._parse_money_value(cols[7].text)
                    medium_net_pct = self._parse_percentage(cols[8].text)
                    small_net = self._parse_money_value(cols[9].text)
                    small_net_pct = self._parse_percentage(cols[10].text)
                    
                    data.append({
                        '日期': date,
                        '主力净流入-净额': main_net,
                        '主力净流入-净占比': main_net_pct,
                        '超大单净流入-净额': super_large_net,
                        '超大单净流入-净占比': super_large_net_pct,
                        '大单净流入-净额': large_net,
                        '大单净流入-净占比': large_net_pct,
                        '中单净流入-净额': medium_net,
                        '中单净流入-净占比': medium_net_pct,
                        '小单净流入-净额': small_net,
                        '小单净流入-净占比': small_net_pct
                    })
            
            # 创建DataFrame
            df = pd.DataFrame(data)
            return df
        except Exception as e:
            print(f"爬虫获取资金流向数据失败: {e}")
            return pd.DataFrame()
    
    def _parse_money_value(self, text: str) -> float:
        """解析金额文本为数值
        
        Args:
            text: 金额文本，如"1.23亿"、"-5,678.90万"
            
        Returns:
            转换后的数值（单位：元）
        """
        try:
            text = text.strip()
            if not text or text == '--':
                return 0.0
                
            # 移除逗号
            text = text.replace(',', '')
            
            # 处理单位
            multiplier = 1.0
            if '亿' in text:
                multiplier = 100000000
                text = text.replace('亿', '')
            elif '万' in text:
                multiplier = 10000
                text = text.replace('万', '')
                
            # 转换为浮点数并应用单位
            value = float(text) * multiplier
            return value
        except Exception:
            return 0.0
    
    def _parse_percentage(self, text: str) -> float:
        """解析百分比文本为数值
        
        Args:
            text: 百分比文本，如"12.34%"
            
        Returns:
            转换后的百分比值
        """
        try:
            text = text.strip()
            if not text or text == '--':
                return 0.0
                
            # 移除百分号并转换为浮点数
            value = float(text.replace('%', ''))
            return value
        except Exception:
            return 0.0
    
    def get_north_money(self, start_date: str, end_date: str) -> Optional[Dict]:
        """获取北向资金流向数据
        
        Args:
            start_date: 开始日期，格式YYYYMMDD
            end_date: 结束日期，格式YYYYMMDD
            
        Returns:
            包含北向资金流向数据的字典
        """
        try:
            # 使用 AKShare 获取北向资金数据
            df = ak.stock_hsgt_north_net_flow_in()
            
            if df.empty:
                # 如果AKShare获取失败，尝试使用爬虫方式获取
                print("AKShare获取北向资金数据失败，尝试使用爬虫方式获取...")
                df = self._crawl_north_money_data()
                if df.empty:
                    return None
            
            # 处理日期格式并筛选日期范围
            df['trade_date'] = pd.to_datetime(df['日期']).dt.strftime('%Y%m%d')
            df = df[(df['trade_date'] >= start_date) & (df['trade_date'] <= end_date)]
            
            # 按日期升序排序
            df = df.sort_values('trade_date')
            
            return {
                'trade_date': df['trade_date'].values,
                'north_money': df['沪股通'].values + df['深股通'].values,  # 北向资金
                'south_money': df['港股通(沪)'].values + df['港股通(深)'].values,  # 南向资金
                'north_money_net': (df['沪股通'].values + df['深股通'].values) - 
                                  (df['港股通(沪)'].values + df['港股通(深)'].values)  # 北向资金净流入
            }
        except Exception as e:
            print(f"获取北向资金流向数据失败: {e}")
            # 尝试使用爬虫方式获取
            try:
                print("尝试使用爬虫方式获取北向资金数据...")
                df = self._crawl_north_money_data()
                if df.empty:
                    return None
                
                # 处理日期格式并筛选日期范围
                df['trade_date'] = pd.to_datetime(df['日期']).dt.strftime('%Y%m%d')
                df = df[(df['trade_date'] >= start_date) & (df['trade_date'] <= end_date)]
                
                # 按日期升序排序
                df = df.sort_values('trade_date')
                
                return {
                    'trade_date': df['trade_date'].values,
                    'north_money': df['沪股通'].values + df['深股通'].values,  # 北向资金
                    'south_money': df['港股通(沪)'].values + df['港股通(深)'].values,  # 南向资金
                    'north_money_net': (df['沪股通'].values + df['深股通'].values) - 
                                      (df['港股通(沪)'].values + df['港股通(深)'].values)  # 北向资金净流入
                }
            except Exception as e2:
                print(f"爬虫获取北向资金数据也失败: {e2}")
                return None
    
    def _crawl_north_money_data(self) -> pd.DataFrame:
        """使用爬虫方式获取北向资金流向数据
        
        Returns:
            包含北向资金流向数据的DataFrame
        """
        try:
            # 构建东方财富网北向资金页面URL
            url = "http://data.eastmoney.com/hsgt/index.html"
            
            # 发送请求获取页面内容
            response = requests.get(url, headers=self.headers, timeout=10)
            response.encoding = 'utf-8'
            
            if response.status_code != 200:
                print(f"请求失败，状态码: {response.status_code}")
                return pd.DataFrame()
            
            # 使用BeautifulSoup解析HTML
            soup = BeautifulSoup(response.text, 'html.parser')
            
            # 查找北向资金数据表格
            table = soup.find('table', id='historical_data')
            if not table:
                print("未找到北向资金数据表格")
                return pd.DataFrame()
            
            # 解析表格数据
            rows = table.find_all('tr')
            data = []
            
            for row in rows[1:]:  # 跳过表头行
                cols = row.find_all('td')
                if len(cols) >= 7:  # 确保列数足够
                    date = cols[0].text.strip()
                    sh_in = self._parse_money_value(cols[1].text)
                    sz_in = self._parse_money_value(cols[2].text)
                    sh_out = self._parse_money_value(cols[3].text)
                    sz_out = self._parse_money_value(cols[4].text)
                    
                    data.append({
                        '日期': date,
                        '沪股通': sh_in,
                        '深股通': sz_in,
                        '港股通(沪)': sh_out,
                        '港股通(深)': sz_out
                    })
            
            # 创建DataFrame
            df = pd.DataFrame(data)
            return df
        except Exception as e:
            print(f"爬虫获取北向资金数据失败: {e}")
            return pd.DataFrame()
            
    def get_industry_capital_flow(self, trade_date: str) -> Optional[Dict]:
        """获取行业板块资金流向数据
        
        Args:
            trade_date: 交易日期，格式YYYYMMDD
            
        Returns:
            包含行业板块资金流向数据的字典
        """